/*
 * Created on Jul 13, 2004
 */
package cheme.ProcessEditor.DirectEdit;

import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.tools.CellEditorLocator;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ICellEditorListener;
import org.eclipse.jface.viewers.ICellEditorValidator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.events.VerifyListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Text;

import cheme.ProcessEditor.LeafFigureNavigator;
import cheme.ProcessModel.Table.WritableField;

/**
 * A generic DirectEdit manager to be used for labels which includes validation
 * functionality by adding the ICellEditorValidator on startup
 */
public class ChemeTextDirectEditManager extends ChemeExtendedDirectEditManager
{
	protected VerifyListener verifyListener;
	private boolean listenersHooked = false;
	
	public ChemeTextDirectEditManager(GraphicalEditPart source, Class editorType, CellEditorLocator locator, Label label, ICellEditorValidator validator)
	{
		super(source, editorType, locator, label, validator);
	}
	
	/**
	 * @see org.eclipse.gef.tools.DirectEditManager#initCellEditor()
	 */
	protected void initCellEditor()
	{
		final EditPart parent = getEditPart().getParent();
		final int originIndex = parent.getChildren().indexOf(getEditPart());
		
		Text text = (Text) getCellEditor().getControl();

		//add the verifyListener to apply changes to the control size
		verifyListener = new VerifyListener()
		{

			/**
			 * Changes the size of the editor control to reflect the changed
			 * text
			 */
			public void verifyText(VerifyEvent event)
			{
				Text text = (Text) getCellEditor().getControl();
				String oldText = text.getText();
				String leftText = oldText.substring(0, event.start);
				String rightText = oldText.substring(event.end, oldText.length());
				GC gc = new GC(text);
				if (leftText == null)
				{
					leftText = "";
				}
				
				if (rightText == null)
				{
					rightText = "";
				}

				Point size = gc.textExtent(leftText + event.text + rightText);

				gc.dispose();
				if (size.x != 0)
				{
					size = text.computeSize(size.x, SWT.DEFAULT);
				}
				else
				{
					//just make it square
					size.x = size.y;
				}
				getCellEditor().getControl().setSize(size.x, size.y);
			}

		};
		text.addVerifyListener(verifyListener);
		
		getCellEditor().addListener(new ICellEditorListener()
		{
			public void applyEditorValue()
			{
				/*
				 * The execution of a command could result in the this manager's editpart
				 * reference being removed from the tree and invalidated. Attempts to navigate to
				 * it will yield exceptions. Try to detect and prevent at least the error, cant think of
				 * a nice way to monitor for changed editparts jsut yet.
				 */
				
				EditPart currentChild = getEditPart();
				int newSize =  parent.getChildren().size();
				
				if(!currentChild.isActive() && null != parent)
				{
					if(newSize > originIndex)
					{
						int newIndex = originIndex + (newSize - originIndex - 1);
						currentChild = (EditPart)parent.getChildren().get(newIndex);
					}
					else if(newSize > 0)
					{
						currentChild = (EditPart)parent.getChildren().get(parent.getChildren().size() - 1);
					}
				}
				
				LeafFigureNavigator.navigateTo((GraphicalEditPart)currentChild);
			}

			public void cancelEditor()
			{
				LeafFigureNavigator.navigateTo((GraphicalEditPart)getEditPart());
			}

			public void editorValueChanged(boolean oldValidState, boolean newValidState)
			{
			}
		});

		//set the initial value of the
		originalValue = ((WritableField)getEditPart().getModel()).getText();
		getCellEditor().setValue(originalValue);

		//calculate the font size of the underlying
		IFigure figure = ((GraphicalEditPart) getEditPart()).getFigure();
		figureFont = figure.getFont();
		FontData data = figureFont.getFontData()[0];
		Dimension fontSize = new Dimension(0, data.getHeight());

		//set the font to be used
		this.label.translateToAbsolute(fontSize);
		data.setHeight(fontSize.height);
		figureFont = new Font(null, data);

		//set the validator for the CellEditor
		getCellEditor().setValidator(validator);

		LeafFigureNavigator.deselect((GraphicalEditPart)getEditPart());
		
		text.setFont(figureFont);
		text.selectAll();
	}
	
	@Override
	protected void setCellEditor(CellEditor editor)
	{
		if(null != editor)
		{
			listenersHooked = true;
		}
		
		super.setCellEditor(editor);
	}
	
	/**
	 * Need to override so as to remove the verify listener
	 */
	protected void unhookListeners()
	{
		/*
		 * Ensure that listeners are only unhooked once. 
		 */
		
		if(listenersHooked)
		{
			listenersHooked = false;
			
			super.unhookListeners();
			Text text = (Text) getCellEditor().getControl();
			text.removeVerifyListener(verifyListener);
			verifyListener = null;
		}
	}
}